package com.ssy.lingxi.pay.serviceimpl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.crypto.digest.DigestUtil;
import cn.hutool.json.JSON;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.github.binarywang.wxpay.bean.order.WxPayAppOrderResult;
import com.github.binarywang.wxpay.bean.order.WxPayMwebOrderResult;
import com.github.binarywang.wxpay.bean.request.*;
import com.github.binarywang.wxpay.bean.result.*;
import com.github.binarywang.wxpay.config.WxPayConfig;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl;
import com.github.binarywang.wxpay.util.SignUtils;
import com.ssy.lingxi.common.constant.Constants;
import com.ssy.lingxi.common.constant.order.OrderPayChannelEnum;
import com.ssy.lingxi.common.constant.order.OrderPaymentParameterEnum;
import com.ssy.lingxi.common.exception.BusinessException;
import com.ssy.lingxi.common.response.ResponseCode;
import com.ssy.lingxi.common.response.Wrapper;
import com.ssy.lingxi.component.redis.service.IRedisUtils;
import com.ssy.lingxi.order.api.feign.OrderFeignService;
import com.ssy.lingxi.order.api.model.vo.request.OrderPayChannelFeignVO;
import com.ssy.lingxi.order.api.model.vo.request.OrderPayParameterFeignVO;
import com.ssy.lingxi.order.api.model.vo.response.PayChannelParameterFeignDetailVO;
import com.ssy.lingxi.order.api.model.vo.response.PaymentParameterFeignDetailVO;
import com.ssy.lingxi.pay.api.common.PayChannelEnum;
import com.ssy.lingxi.pay.api.dto.request.*;
import com.ssy.lingxi.pay.common.WechatErrorEnum;
import com.ssy.lingxi.pay.config.PayGateWayConfig;
import com.ssy.lingxi.pay.model.assetAccount.*;
import com.ssy.lingxi.pay.model.dto.UrlLinkDTO;
import com.ssy.lingxi.pay.service.IPayCacheService;
import com.ssy.lingxi.pay.service.IWeChatPayService;
import com.ssy.lingxi.pay.utils.RestTemplateUtil;
import com.ssy.lingxi.pay.utils.WeChatPayUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * 微信支付类
 *
 * @author jw.chen
 */
@Service
public class WeChatPayServiceImpl implements IWeChatPayService {
    @Autowired
    private PayGateWayConfig payGateWayConfig;

    @Resource
    private IPayCacheService payCacheService;

    @Resource
    private OrderFeignService orderFeignService;

    @Resource
    private RestTemplateUtil restTemplateUtil;

    @Resource
    private IRedisUtils redisUtils;

    /**
     * 获取access_token的接口地址（GET） 限200（次/天）
     */
    public final static String access_token_url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";
    /**
     * 获取小程序 URL Link(POST)
     */
    public final static String generate_url_link = "https://api.weixin.qq.com/wxa/generate_urllink?access_token=ACCESS_TOKEN";


    /**
     * 获取JsApiTicket
     */
    public final static String ticket_url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi";

    private Logger logger = LoggerFactory.getLogger(WeChatPayServiceImpl.class);

    /**
     * native支付(生成二维码，通过手机扫描二维码调起微信支付)
     */
    @Override
    public PayResult nativePay(MobilePayRequest mobilePayRequest, HttpServletRequest request) {
        //从订单服务查询支付参数
        if (StringUtils.isAnyEmpty(mobilePayRequest.getMerchantId(), mobilePayRequest.getApiKey(), mobilePayRequest.getAppId())) {
            OrderPayParameterFeignVO feignVO = new OrderPayParameterFeignVO();
            feignVO.setMemberId(mobilePayRequest.getMemberId());
            feignVO.setRoleId(mobilePayRequest.getMemberRoleId());
            feignVO.setPayChannel(OrderPayChannelEnum.WECHAT_PAY);
            Wrapper<PaymentParameterFeignDetailVO> parameterResult = orderFeignService.findPaymentParameters(feignVO);
            if (parameterResult.getCode() != ResponseCode.SUCCESS.getCode()) {
                return new PayResult(false, parameterResult.getMessage());
            }

            if (CollectionUtils.isEmpty(parameterResult.getData().getParameters())) {
                return new PayResult(false, ResponseCode.PAY_PLATFORM_PARAMETERS_DOES_NOT_EXIST.getMessage());
            }

            parameterResult.getData().getParameters().forEach(p -> {
                if (p.getParameter().equals(OrderPaymentParameterEnum.WECHAT_MERCHANT_ID)) {
                    mobilePayRequest.setMerchantId(p.getValue());
                } else if (p.getParameter().equals(OrderPaymentParameterEnum.WECHAT_APP_ID)) {
                    mobilePayRequest.setAppId(p.getValue());
                } else if (p.getParameter().equals(OrderPaymentParameterEnum.WECHAT_API_KEY)) {
                    mobilePayRequest.setApiKey(p.getValue());
                }
            });
        }

        //生成用于缓存Key的随机字符串，并作为透传参数传递给微信支付，在返回时从缓存中查询秘钥信息
        if (StringUtils.isEmpty(mobilePayRequest.getNonce())) {
            mobilePayRequest.setNonce(payCacheService.randomString());
        }

        //缓存支付参数
        payCacheService.cacheWeChatPayParameters(mobilePayRequest.getMemberId(), mobilePayRequest.getMemberRoleId(), mobilePayRequest.getPayType(), mobilePayRequest.getNonce(), mobilePayRequest.getMerchantId(), mobilePayRequest.getAppId(), mobilePayRequest.getApiKey());

        //获取参数
        String orderCode = mobilePayRequest.getOrderCode();
        Double payMoney = mobilePayRequest.getPayMoney();
        String remark = mobilePayRequest.getRemark();
        String attach = mobilePayRequest.getAttach();
        Long memberId = mobilePayRequest.getMemberId();
        Long memberRoleId = mobilePayRequest.getMemberRoleId();
        String serviceType = mobilePayRequest.getServiceType();
        Integer payType = mobilePayRequest.getPayType();

        //封装微信附加数据
        //由于微信附加信息最长128字符，所以改为用ObjectMapper进行序列化，同时AttachInfo的每个字段增加了@JsonProperty注解
        //这样可以简短附加数据的长度
        AttachInfo attachInfo = new AttachInfo();
        attachInfo.setPayType(payType);
        attachInfo.setMemberId(memberId);
        attachInfo.setMemberRoleId(memberRoleId);
        attachInfo.setAttach(attach);
        attachInfo.setServiceType(serviceType);
        attachInfo.setNonce(mobilePayRequest.getNonce());
        String attachJson = payCacheService.serializeObject(attachInfo);
        //微信支付需要的参数
        Map<String, String> paramMap = new HashMap<>();
        paramMap.put("appid", mobilePayRequest.getAppId());                                         //程序ID
        paramMap.put("mch_id", mobilePayRequest.getMerchantId());                                   //商户号
        paramMap.put("nonce_str", WeChatPayUtil.getNonceStr());                                     //随机字符串
        paramMap.put("body", remark);                                                               //商品描述
        paramMap.put("out_trade_no", orderCode);                                                    //商户订单号
        paramMap.put("total_fee", String.valueOf(new Double(payMoney * 100).longValue()));    //交易金额
        paramMap.put("spbill_create_ip", WeChatPayUtil.getRemoteAddrIp(request));                   //客户端id
        paramMap.put("notify_url", payGateWayConfig.getNotifyUrl() + WeChatPayUtil.notifyUrl);      //支付结果通知的回调地址
        paramMap.put("trade_type", WeChatPayUtil.NATIVE);                                           //交易类型
        if(StringUtils.isNotEmpty(attachJson)){                                                     //附加数据
            paramMap.put("attach", attachJson);
        }
        try{
            //生成签名
            String sign = WeChatPayUtil.createSign(paramMap, mobilePayRequest.getApiKey(), "UTF-8");
            paramMap.put("sign", sign);
            //验证必填项
            if (StringUtils.isEmpty(paramMap.get("appid"))) {
                return new PayResult(false, "appid 参数为空");
            }
            if (StringUtils.isEmpty(paramMap.get("mch_id"))) {
                return new PayResult(false, "mch_id 参数为空");
            }
            if (StringUtils.isEmpty(paramMap.get("nonce_str"))) {
                return new PayResult(false, "nonce_str 参数为空");
            }
            if (StringUtils.isEmpty(paramMap.get("body"))) {
                return new PayResult(false, "body 参数为空");
            }
            if (StringUtils.isEmpty(paramMap.get("out_trade_no"))) {
                return new PayResult(false, "out_trade_no 参数为空");
            }
            if (StringUtils.isEmpty(paramMap.get("total_fee"))) {
                return new PayResult(false, "total_fee 参数为空");
            }
            if (StringUtils.isEmpty(paramMap.get("spbill_create_ip"))) {
                return new PayResult(false, "spbill_create_ip 参数为空");
            }
            if (StringUtils.isEmpty(paramMap.get("notify_url"))) {
                return new PayResult(false, "notify_url 参数为空");
            }
            if (StringUtils.isEmpty(paramMap.get("trade_type"))) {
                return new PayResult(false, "trade_type 参数为空");
            }
            if (StringUtils.isEmpty(sign)) {
                return new PayResult(false, "sign 参数为空");
            }

            //参数转成XML
            String requestXML = WeChatPayUtil.getRequestXml(paramMap);
            //预支付
            String resultXML = WeChatPayUtil.httpsRequest(WeChatPayUtil.payUrl, "POST", requestXML);
            //返回结果转成Map
            Map<String, String> resultMap = WeChatPayUtil.xmlToMap(resultXML);
            //验证返回结果
            String returnCode = resultMap.get("return_code");
            if (WeChatPayUtil.SUCCESS.equals(returnCode)) {
                //验证支付结果
                String resultCode = resultMap.get("result_code");
                if (WeChatPayUtil.SUCCESS.equals(resultCode)) {
                    Map<String, String> result = new HashMap<String, String>();
                    //返回支付url,页面生成二维码
                    result.put("code_url", resultMap.get("code_url"));
                    return new PayResult(true, result);
                } else {
                    return new PayResult(false, resultMap.get("err_code_des"));
                }
            }
            //返回错误信息
            return new PayResult(false, resultMap.get("return_msg"));
        } catch (Exception e) {
            e.printStackTrace();
            throw new BusinessException(ResponseCode.PAY_MEMBER_PAY_FAIL);
        }
    }

    /**
     * app支付(在app软件中直接调起微信支付)
     */
    @Override
    public PayResult appPay(MobilePayRequest mobilePayRequest, HttpServletRequest request) {
        //从订单服务查询支付参数
        if (StringUtils.isAnyEmpty(mobilePayRequest.getMerchantId(), mobilePayRequest.getApiKey(), mobilePayRequest.getAppId())) {
            OrderPayParameterFeignVO feignVO = new OrderPayParameterFeignVO();
            feignVO.setMemberId(mobilePayRequest.getMemberId());
            feignVO.setRoleId(mobilePayRequest.getMemberRoleId());
            feignVO.setPayChannel(OrderPayChannelEnum.WECHAT_PAY);
            Wrapper<PaymentParameterFeignDetailVO> parameterResult = orderFeignService.findPaymentParameters(feignVO);
            if (parameterResult.getCode() != ResponseCode.SUCCESS.getCode()) {
                return new PayResult(false, parameterResult.getMessage());
            }

            if (CollectionUtils.isEmpty(parameterResult.getData().getParameters())) {
                return new PayResult(false, ResponseCode.PAY_PLATFORM_PARAMETERS_DOES_NOT_EXIST.getMessage());
            }

            parameterResult.getData().getParameters().forEach(p -> {
                if (p.getParameter().equals(OrderPaymentParameterEnum.WECHAT_MERCHANT_ID)) {
                    mobilePayRequest.setMerchantId(p.getValue());
                } else if (p.getParameter().equals(OrderPaymentParameterEnum.WECHAT_APP_ID)) {
                    mobilePayRequest.setAppId(p.getValue());
                } else if (p.getParameter().equals(OrderPaymentParameterEnum.WECHAT_API_KEY)) {
                    mobilePayRequest.setApiKey(p.getValue());
                }
            });
        }

        //生成用于缓存Key的随机字符串，并作为透传参数传递给微信支付，在返回时从缓存中查询秘钥信息
        if (StringUtils.isEmpty(mobilePayRequest.getNonce())) {
            mobilePayRequest.setNonce(payCacheService.randomString());
        }

        //缓存支付参数
        payCacheService.cacheWeChatPayParameters(mobilePayRequest.getMemberId(), mobilePayRequest.getMemberRoleId(), mobilePayRequest.getPayType(), mobilePayRequest.getNonce(), mobilePayRequest.getMerchantId(), mobilePayRequest.getAppId(), mobilePayRequest.getApiKey());

        //获取参数
        String orderCode = mobilePayRequest.getOrderCode();
        Double payMoney = mobilePayRequest.getPayMoney();
        String remark = mobilePayRequest.getRemark();
        String attach = mobilePayRequest.getAttach();
        Long memberId = mobilePayRequest.getMemberId();
        Long memberRoleId = mobilePayRequest.getMemberRoleId();
        String serviceType = mobilePayRequest.getServiceType();
        Integer payType = mobilePayRequest.getPayType();

        //封装微信附加数据
        AttachInfo attachInfo = new AttachInfo();
        attachInfo.setPayType(payType);
        attachInfo.setMemberId(memberId);
        attachInfo.setMemberRoleId(memberRoleId);
        attachInfo.setAttach(attach);
        attachInfo.setServiceType(serviceType);
        attachInfo.setNonce(mobilePayRequest.getNonce());
        String attachJson = payCacheService.serializeObject(attachInfo);
        //微信支付需要的参数
        String nonceStr = WeChatPayUtil.getNonceStr();
        Map<String, String> paramMap = new HashMap<>();
        paramMap.put("appid", mobilePayRequest.getAppId());                                                          //程序ID
        paramMap.put("mch_id", mobilePayRequest.getMerchantId());                                                              //商户号
        paramMap.put("nonce_str", nonceStr);                                                        //随机字符串
        paramMap.put("body", remark);                                                               //商品描述
        paramMap.put("out_trade_no", orderCode);                                                    //商户订单号
        paramMap.put("fee_type", "CNY");                                                            //商户订单号
        paramMap.put("total_fee", String.valueOf(new Double(payMoney * 100).longValue()));    //交易金额
        paramMap.put("trade_type", WeChatPayUtil.APP);                                              //交易类型
        paramMap.put("spbill_create_ip", WeChatPayUtil.getRemoteAddrIp(request));                   //客户端id
        paramMap.put("notify_url", payGateWayConfig.getNotifyUrl() + WeChatPayUtil.notifyUrl);      //支付结果通知的回调地址
        paramMap.put("sign_type", "MD5");                                                           //签名类型
        if (StringUtils.isNotEmpty(attachJson)) {                                                     //附加数据
            paramMap.put("attach", attachJson);
        }
        try {
            //生成签名
            String sign = WeChatPayUtil.createSign(paramMap, mobilePayRequest.getApiKey(), "UTF-8");
            paramMap.put("sign", sign);
            //验证必填项
            if (StringUtils.isEmpty(paramMap.get("appid"))) {
                return new PayResult(false, "appid 参数为空");
            }
            if (StringUtils.isEmpty(paramMap.get("mch_id"))) {
                return new PayResult(false, "mch_id 参数为空");
            }
            if (StringUtils.isEmpty(paramMap.get("nonce_str"))) {
                return new PayResult(false, "nonce_str 参数为空");
            }
            if (StringUtils.isEmpty(paramMap.get("body"))) {
                return new PayResult(false, "body 参数为空");
            }
            if (StringUtils.isEmpty(paramMap.get("out_trade_no"))) {
                return new PayResult(false, "out_trade_no 参数为空");
            }
            if (StringUtils.isEmpty(paramMap.get("total_fee"))) {
                return new PayResult(false, "total_fee 参数为空");
            }
            if (StringUtils.isEmpty(paramMap.get("spbill_create_ip"))) {
                return new PayResult(false, "spbill_create_ip 参数为空");
            }
            if (StringUtils.isEmpty(paramMap.get("notify_url"))) {
                return new PayResult(false, "notify_url 参数为空");
            }
            if (StringUtils.isEmpty(paramMap.get("trade_type"))) {
                return new PayResult(false, "trade_type 参数为空");
            }
            if (StringUtils.isEmpty(sign)) {
                return new PayResult(false, "sign 参数为空");
            }

            //参数转成XML
            String requestXML = WeChatPayUtil.getRequestXml(paramMap);
            //预支付
            String resultXML = WeChatPayUtil.httpsRequest(WeChatPayUtil.payUrl, "POST", requestXML);
            //返回结果转成Map
            Map<String, String> resultMap = WeChatPayUtil.xmlToMap(resultXML);
            //验证返回结果
            String returnCode = resultMap.get("return_code");
            if (WeChatPayUtil.SUCCESS.equals(returnCode)) {
                //验证支付结果
                String resultCode = resultMap.get("result_code");
                if (WeChatPayUtil.SUCCESS.equals(resultCode)) {
                    //获取统一下单接口返回的prepay_id
                    String prepay_id = resultMap.get("prepay_id");
                    //组装返回到app页面参数
                    Map<String, String> result = new HashMap<>();
                    result.put("appid", mobilePayRequest.getAppId());
                    result.put("partnerid", mobilePayRequest.getMerchantId());
                    result.put("prepayid", prepay_id);
                    result.put("noncestr", nonceStr);
                    result.put("timestamp", String.valueOf(System.currentTimeMillis() / 1000));
                    result.put("package", "Sign=WXPay");
                    //生成签名
                    sign = WeChatPayUtil.createSign(result, mobilePayRequest.getApiKey(), "UTF-8");
                    result.put("sign", sign);
                    System.out.println(result);
                    //删除关键信息
                    result.remove("appid");
                    result.remove("package");
                    return new PayResult(true, result);
                } else {
                    return new PayResult(false, resultMap.get("err_code_des"));
                }
            }
            //返回错误信息
            return new PayResult(false, resultMap.get("return_msg"));
        } catch (Exception e) {
            e.printStackTrace();
            throw new BusinessException(ResponseCode.PAY_MEMBER_PAY_FAIL);
        }
    }

    /**
     * JSAPI支付(小程序调起微信支付)
     */
    @Override
    public PayResult jsAPIPay(MobilePayRequest mobilePayRequest, HttpServletRequest request) {
        //从订单服务查询支付参数
        if (StringUtils.isAnyEmpty(mobilePayRequest.getMerchantId(), mobilePayRequest.getApiKey(), mobilePayRequest.getAppId(), mobilePayRequest.getAppKey())) {
            OrderPayParameterFeignVO feignVO = new OrderPayParameterFeignVO();
            feignVO.setMemberId(mobilePayRequest.getMemberId());
            feignVO.setRoleId(mobilePayRequest.getMemberRoleId());
            feignVO.setPayChannel(OrderPayChannelEnum.WECHAT_PAY);
            Wrapper<PaymentParameterFeignDetailVO> parameterResult = orderFeignService.findPaymentParameters(feignVO);
            if (parameterResult.getCode() != ResponseCode.SUCCESS.getCode()) {
                return new PayResult(false, parameterResult.getMessage());
            }

            if (CollectionUtils.isEmpty(parameterResult.getData().getParameters())) {
                return new PayResult(false, ResponseCode.PAY_PLATFORM_PARAMETERS_DOES_NOT_EXIST.getMessage());
            }

            parameterResult.getData().getParameters().forEach(p -> {
                if (p.getParameter().equals(OrderPaymentParameterEnum.WECHAT_MERCHANT_ID)) {
                    mobilePayRequest.setMerchantId(p.getValue());
                } else if (p.getParameter().equals(OrderPaymentParameterEnum.WECHAT_API_KEY)) {
                    mobilePayRequest.setApiKey(p.getValue());
                } else if (p.getParameter().equals(OrderPaymentParameterEnum.WECHAT_APPLET_APP_ID)) {
                    mobilePayRequest.setAppletAppId(p.getValue());
                } else if (p.getParameter().equals(OrderPaymentParameterEnum.WECHAT_APPLET_APP_KEY)) {
                    mobilePayRequest.setAppletAppKey(p.getValue());
                }
            });
        }

        //生成用于缓存Key的随机字符串，并作为透传参数传递给微信支付，在返回时从缓存中查询秘钥信息
        if (StringUtils.isEmpty(mobilePayRequest.getNonce())) {
            mobilePayRequest.setNonce(payCacheService.randomString());
        }

        //缓存支付参数
        payCacheService.cacheWeChatPayParameters(mobilePayRequest.getMemberId(), mobilePayRequest.getMemberRoleId(), mobilePayRequest.getPayType(), mobilePayRequest.getNonce(), mobilePayRequest.getMerchantId(), mobilePayRequest.getAppId(), mobilePayRequest.getApiKey());

        //获取参数
        String orderCode = mobilePayRequest.getOrderCode();
        Double payMoney = mobilePayRequest.getPayMoney();
        String remark = mobilePayRequest.getRemark();
        String attach = mobilePayRequest.getAttach();
        Long memberId = mobilePayRequest.getMemberId();
        Long memberRoleId = mobilePayRequest.getMemberRoleId();
        String serviceType = mobilePayRequest.getServiceType();
        Integer payType = mobilePayRequest.getPayType();
        String appletAppId = mobilePayRequest.getAppletAppId();
        String appletAppKey = mobilePayRequest.getAppletAppKey();
        String merchantId = mobilePayRequest.getMerchantId();
        String jsCode = mobilePayRequest.getJsCode();
        String apiKey = mobilePayRequest.getApiKey();

        //封装微信附加数据
        //由于微信附加信息最长128字符，所以改为用ObjectMapper进行序列化，同时AttachInfo的每个字段增加了@JsonProperty注解
        //这样可以简短附加数据的长度
        AttachInfo attachInfo = new AttachInfo();
        attachInfo.setPayType(payType);
        attachInfo.setMemberId(memberId);
        attachInfo.setMemberRoleId(memberRoleId);
        attachInfo.setAttach(attach);
        attachInfo.setServiceType(serviceType);
        attachInfo.setNonce(mobilePayRequest.getNonce());
        String attachJson = payCacheService.serializeObject(attachInfo);
        //微信支付需要的参数
        Map<String, String> paramMap = new HashMap<>();
        paramMap.put("appid", appletAppId);                                                         //程序ID
        paramMap.put("mch_id", merchantId);                                                         //商户号
        paramMap.put("nonce_str", WeChatPayUtil.getNonceStr());                                     //随机字符串
        paramMap.put("body", remark);                                                               //商品描述
        paramMap.put("out_trade_no", orderCode);                                                    //商户订单号
        paramMap.put("total_fee", String.valueOf(new Double(payMoney * 100).longValue()));    //交易金额
        paramMap.put("spbill_create_ip", WeChatPayUtil.getRemoteAddrIp(request));                   //客户端ip
        paramMap.put("notify_url", payGateWayConfig.getNotifyUrl() + WeChatPayUtil.notifyUrl);      //支付结果通知的回调地址
        paramMap.put("time_start", String.valueOf(System.currentTimeMillis() / 1000));              //交易时间
        paramMap.put("trade_type", WeChatPayUtil.JS_API);                                           //交易类型
        if (StringUtils.isNotEmpty(attachJson)) {                                                     //附加数据
            paramMap.put("attach", attachJson);
        }
        //获取openId
        String param = "appid=" + appletAppId + "&secret=" + appletAppKey + "&js_code=" + jsCode + "&grant_type=" + WeChatPayUtil.GRANT_TYPE;
        String resultStr = WeChatPayUtil.httpsRequest(WeChatPayUtil.loginUrl, "POST", param);
        Map<String, String> map = (Map<String, String>) JSONUtil.toBean(resultStr, Map.class);
        String openId = map.get("openid");
        if (openId != null && !"".equals(openId)) {
            paramMap.put("openid", openId);
        } else {
            return new PayResult(false, "获取openid参数出错!");
        }

        try {
            //生成签名
            String sign = WeChatPayUtil.createSign(paramMap, apiKey, "UTF-8");
            paramMap.put("sign", sign);
            //验证必填项
            if (StringUtils.isEmpty(paramMap.get("appid"))) {
                return new PayResult(false, "appid 参数为空");
            }
            if (StringUtils.isEmpty(paramMap.get("mch_id"))) {
                return new PayResult(false, "mch_id 参数为空");
            }
            if (StringUtils.isEmpty(paramMap.get("nonce_str"))) {
                return new PayResult(false, "nonce_str 参数为空");
            }
            if (StringUtils.isEmpty(paramMap.get("body"))) {
                return new PayResult(false, "body 参数为空");
            }
            if (StringUtils.isEmpty(paramMap.get("out_trade_no"))) {
                return new PayResult(false, "out_trade_no 参数为空");
            }
            if (StringUtils.isEmpty(paramMap.get("total_fee"))) {
                return new PayResult(false, "total_fee 参数为空");
            }
            if (StringUtils.isEmpty(paramMap.get("spbill_create_ip"))) {
                return new PayResult(false, "spbill_create_ip 参数为空");
            }
            if (StringUtils.isEmpty(paramMap.get("notify_url"))) {
                return new PayResult(false, "notify_url 参数为空");
            }
            if (StringUtils.isEmpty(paramMap.get("trade_type"))) {
                return new PayResult(false, "trade_type 参数为空");
            }
            if (StringUtils.isEmpty(sign)) {
                return new PayResult(false, "sign 参数为空");
            }

            //参数转成XML
            String requestXML = WeChatPayUtil.getRequestXml(paramMap);
            //预支付
            String resultXML = WeChatPayUtil.httpsRequest(WeChatPayUtil.payUrl, "POST", requestXML);
            //返回结果转成Map
            Map<String, String> resultMap = WeChatPayUtil.xmlToMap(resultXML);
            //验证返回结果
            String returnCode = resultMap.get("return_code");
            if (WeChatPayUtil.SUCCESS.equals(returnCode)) {
                //验证支付结果
                String resultCode = resultMap.get("result_code");
                if (WeChatPayUtil.SUCCESS.equals(resultCode)) {
                    //获取统一下单接口返回的prepay_id
                    String prepay_id = resultMap.get("prepay_id");
                    //组装返回到小程序页面参数
                    Map<String, String> result = new HashMap<>();
                    result.put("appId", appletAppId);
                    result.put("timeStamp", String.valueOf(System.currentTimeMillis() / 1000));
                    result.put("nonceStr", WeChatPayUtil.getNonceStr());
                    result.put("package", "prepay_id=" + prepay_id);
                    result.put("signType", WeChatPayUtil.SIGN_TYPE);
                    //生成签名
                    sign = WeChatPayUtil.createSign(result, apiKey, "UTF-8");
                    result.put("paySign", sign);
                    return new PayResult(true, result);
                } else {
                    return new PayResult(false, resultMap.get("err_code_des"));
                }
            }
            //返回错误信息
            return new PayResult(false, resultMap.get("return_msg"));
        } catch (Exception e) {
            e.printStackTrace();
            throw new BusinessException(ResponseCode.PAY_MEMBER_PAY_FAIL);
        }
    }

    /**
     * H5支付(微信)
     *
     * @param mobilePayRequest
     * @param request
     * @return
     */
    @Override
    public PayResult h5Pay(MobilePayRequest mobilePayRequest, HttpServletRequest request) {
        //获取参数
        String orderCode = mobilePayRequest.getOrderCode();
        Double payMoney = mobilePayRequest.getPayMoney();
        String remark = mobilePayRequest.getRemark();
        String attach = mobilePayRequest.getAttach();
        Long memberId = mobilePayRequest.getMemberId();
        Long memberRoleId = mobilePayRequest.getMemberRoleId();
        String serviceType = mobilePayRequest.getServiceType();
        Integer payType = mobilePayRequest.getPayType();


        //从订单服务查询支付参数
        if (checkParamIfNull(mobilePayRequest)) {
            Wrapper<PaymentParameterFeignDetailVO> parameterResult = findPayParamsFromOrderService(mobilePayRequest);
            if (parameterResult.getCode() != ResponseCode.SUCCESS.getCode()) {
                return new PayResult(false, parameterResult.getMessage());
            }
            if (CollectionUtils.isEmpty(parameterResult.getData().getParameters())) {
                return new PayResult(false, ResponseCode.PAY_PLATFORM_PARAMETERS_DOES_NOT_EXIST.getMessage());
            }
            resetParams(parameterResult, mobilePayRequest);
        }

        //生成用于缓存Key的随机字符串，并作为透传参数传递给微信支付，在返回时从缓存中查询秘钥信息
        setNonce(mobilePayRequest);

        //随机数生成
        String nonceStr = mobilePayRequest.getNonce();

        //缓存支付参数
        cachePayParams(mobilePayRequest);

        //实例化WxPayService
        WxPayService wxPayService = getWxPayService(mobilePayRequest);

        //封装微信附加数据
        String attachJson = getAttachInfoJson(attach, memberId, memberRoleId, nonceStr,serviceType, payType);

        //封装微信H5统一下单的请求参数
        WxPayUnifiedOrderRequest wxPayUnifiedOrderRequest = getH5WxPayUnifiedOrderRequest(mobilePayRequest, request, nonceStr, orderCode, payMoney, remark, attachJson);

        try {
            //预支付
            WxPayUnifiedOrderResult wxPayUnifiedOrderResult = wxPayService.unifiedOrder(wxPayUnifiedOrderRequest);
            String mwebUrl = wxPayUnifiedOrderResult.getMwebUrl();
            String returnCode = wxPayUnifiedOrderResult.getReturnCode();
            String returnMsg = wxPayUnifiedOrderResult.getReturnMsg();
            String resultCode = wxPayUnifiedOrderResult.getResultCode();
            String errCodeDes = wxPayUnifiedOrderResult.getErrCodeDes();
            if (WeChatPayUtil.SUCCESS.equals(returnCode)) {
                //验证支付结果
                if (WeChatPayUtil.SUCCESS.equals(resultCode)) {
                    //获取统一下单接口返回的mwebUrl
                    return new PayResult(true, getWxPayMwebOrderResult(mwebUrl));
                } else {
                    return new PayResult(false, errCodeDes);
                }
            }
            //返回错误信息
            return new PayResult(false, returnMsg);
        } catch (Exception e) {
            logger.error(e.getMessage());
            throw new BusinessException(ResponseCode.PAY_MEMBER_PAY_FAIL);
        }
    }

    /**
     * H5-获取H5支付地址
     *
     * @param mwebUrl
     * @return
     */
    private WxPayMwebOrderResult getWxPayMwebOrderResult(String mwebUrl) {
        WxPayMwebOrderResult wxPayMwebOrderResult = new WxPayMwebOrderResult();
        wxPayMwebOrderResult.setMwebUrl(mwebUrl);
        return wxPayMwebOrderResult;
    }

    /**
     * H5-封装微信统一下单的请求参数
     *
     * @param mobilePayRequest 请求支付参数
     * @param request          HttpServletRequest
     * @param nonceStr         随机数
     * @param orderCode        订单编号
     * @param payMoney         支付金额
     * @param remark           商品描述
     * @param attachJson       微信附加数据
     * @return
     */
    private WxPayUnifiedOrderRequest getH5WxPayUnifiedOrderRequest(MobilePayRequest mobilePayRequest, HttpServletRequest request, String nonceStr, String orderCode, Double payMoney, String remark, String attachJson) {
        WxPayUnifiedOrderRequest wxPayUnifiedOrderRequest = new WxPayUnifiedOrderRequest();
        wxPayUnifiedOrderRequest.setAppid(mobilePayRequest.getAppId());
        wxPayUnifiedOrderRequest.setMchId(mobilePayRequest.getMerchantId());
        wxPayUnifiedOrderRequest.setNonceStr(nonceStr);
        wxPayUnifiedOrderRequest.setBody(remark);
        wxPayUnifiedOrderRequest.setOutTradeNo(orderCode);
        wxPayUnifiedOrderRequest.setTotalFee(new Double(payMoney * 100).intValue());
        wxPayUnifiedOrderRequest.setSpbillCreateIp(WeChatPayUtil.getRemoteAddrIp(request));
        wxPayUnifiedOrderRequest.setNotifyUrl(payGateWayConfig.getNotifyUrl() + WeChatPayUtil.notifyUrl);
        wxPayUnifiedOrderRequest.setTradeType(WeChatPayUtil.MWEB);
        if (StringUtils.isNotEmpty(attachJson)) {
            wxPayUnifiedOrderRequest.setAttach(attachJson);
        }
        String unifiedOrderSign = SignUtils.createSign(wxPayUnifiedOrderRequest, "MD5", mobilePayRequest.getApiKey(), null);
        wxPayUnifiedOrderRequest.setSign(unifiedOrderSign);
        return wxPayUnifiedOrderRequest;
    }

    /**
     * H5-封装微信附加数据
     *
     * @param attach       请求中的参数，用于回调时校验的
     * @param memberId     会员id
     * @param memberRoleId 角色id
     * @param serviceType  微服务类型
     * @param payType      支付类型
     * @return
     */
    private String getAttachInfoJson(String attach, Long memberId, Long memberRoleId, String norceStr, String serviceType, Integer payType) {
        AttachInfo attachInfo = new AttachInfo();
        attachInfo.setPayType(payType);
        attachInfo.setMemberId(memberId);
        attachInfo.setMemberRoleId(memberRoleId);
        attachInfo.setNonce(norceStr);
        attachInfo.setAttach(attach);
        attachInfo.setServiceType(serviceType);
        return payCacheService.serializeObject(attachInfo);
    }


    /**
     * H5-实例化WxPayService
     *
     * @param mobilePayRequest
     * @return
     */
    private WxPayService getWxPayService(MobilePayRequest mobilePayRequest) {
        WxPayService wxPayService = new WxPayServiceImpl();
        WxPayConfig payConfig = new WxPayConfig();
        payConfig.setMchId(mobilePayRequest.getMerchantId());
        payConfig.setAppId(mobilePayRequest.getAppId());
        payConfig.setMchKey(mobilePayRequest.getApiKey());
        wxPayService.setConfig(payConfig);
        return wxPayService;
    }

    /**
     * H5-缓存支付参数
     *
     * @param mobilePayRequest
     */
    private void cachePayParams(MobilePayRequest mobilePayRequest) {
        payCacheService.cacheWeChatPayParameters(mobilePayRequest.getMemberId(), mobilePayRequest.getMemberRoleId(), mobilePayRequest.getPayType(), mobilePayRequest.getNonce(), mobilePayRequest.getMerchantId(), mobilePayRequest.getAppId(), mobilePayRequest.getApiKey());
    }

    /**
     * H5-生成用于缓存Key的随机字符串，并作为透传参数传递给微信支付，在返回时从缓存中查询秘钥信息
     *
     * @param mobilePayRequest
     */
    private void setNonce(MobilePayRequest mobilePayRequest) {
        if (StringUtils.isEmpty(mobilePayRequest.getNonce())) {
            mobilePayRequest.setNonce(payCacheService.randomString());
        }
    }

    /**
     * H5-重新设置支付参数
     *
     * @param parameterResult
     * @param mobilePayRequest
     * @return
     */
    private void resetParams(Wrapper<PaymentParameterFeignDetailVO> parameterResult, MobilePayRequest mobilePayRequest) {
        parameterResult.getData().getParameters().forEach(p -> {
            if (p.getParameter().equals(OrderPaymentParameterEnum.WECHAT_MERCHANT_ID)) {
                mobilePayRequest.setMerchantId(p.getValue());
            } else if (p.getParameter().equals(OrderPaymentParameterEnum.WECHAT_API_KEY)) {
                mobilePayRequest.setApiKey(p.getValue());
            } else if (p.getParameter().equals(OrderPaymentParameterEnum.WECHAT_APPLET_APP_ID)) {
                mobilePayRequest.setAppletAppId(p.getValue());
            } else if (p.getParameter().equals(OrderPaymentParameterEnum.WECHAT_APPLET_APP_KEY)) {
                mobilePayRequest.setAppletAppKey(p.getValue());
            }
        });
    }

    /**
     * H5-从订单服务中获取支付参数
     *
     * @param mobilePayRequest
     * @return
     */
    private Wrapper<PaymentParameterFeignDetailVO> findPayParamsFromOrderService(MobilePayRequest mobilePayRequest) {
        OrderPayParameterFeignVO feignVO = new OrderPayParameterFeignVO();
        feignVO.setMemberId(mobilePayRequest.getMemberId());
        feignVO.setRoleId(mobilePayRequest.getMemberRoleId());
        feignVO.setPayChannel(OrderPayChannelEnum.WECHAT_PAY);
        return orderFeignService.findPaymentParameters(feignVO);
    }

    /**
     * H5-校验支付必要参数是否为空
     *
     * @param mobilePayRequest
     * @return
     */
    private boolean checkParamIfNull(MobilePayRequest mobilePayRequest) {
        return StringUtils.isAnyEmpty(
                mobilePayRequest.getMerchantId(),
                mobilePayRequest.getApiKey(),
                mobilePayRequest.getAppId(),
                mobilePayRequest.getAppKey());
    }

    /**
     * app支付
     */
    @Override
    public PayResult appPay_new(MobilePayRequest mobilePayRequest, HttpServletRequest request) {
        //获取参数
        String orderCode = mobilePayRequest.getOrderCode();
        Double payMoney = mobilePayRequest.getPayMoney();
        String remark = mobilePayRequest.getRemark();
        String attach = mobilePayRequest.getAttach();
        Long memberId = mobilePayRequest.getMemberId();
        Long memberRoleId = mobilePayRequest.getMemberRoleId();
        String serviceType = mobilePayRequest.getServiceType();
        Integer payType = mobilePayRequest.getPayType();
        //获取支付参数
        //从订单服务查询支付参数
        if (StringUtils.isAnyEmpty(mobilePayRequest.getMerchantId(), mobilePayRequest.getApiKey(), mobilePayRequest.getAppId())) {
            OrderPayParameterFeignVO feignVO = new OrderPayParameterFeignVO();
            feignVO.setMemberId(mobilePayRequest.getMemberId());
            feignVO.setRoleId(mobilePayRequest.getMemberRoleId());
            feignVO.setPayChannel(OrderPayChannelEnum.WECHAT_PAY);
            Wrapper<PaymentParameterFeignDetailVO> parameterResult = orderFeignService.findPaymentParameters(feignVO);
            if(parameterResult.getCode() != ResponseCode.SUCCESS.getCode()) {
                return new PayResult(false, parameterResult.getMessage());
            }

            if (CollectionUtils.isEmpty(parameterResult.getData().getParameters())) {
                return new PayResult(false, ResponseCode.PAY_PLATFORM_PARAMETERS_DOES_NOT_EXIST.getMessage());
            }

            parameterResult.getData().getParameters().forEach(p -> {
                if (p.getParameter().equals(OrderPaymentParameterEnum.WECHAT_MERCHANT_ID)) {
                    mobilePayRequest.setMerchantId(p.getValue());
                } else if (p.getParameter().equals(OrderPaymentParameterEnum.WECHAT_APP_ID)) {
                    mobilePayRequest.setAppId(p.getValue());
                } else if (p.getParameter().equals(OrderPaymentParameterEnum.WECHAT_API_KEY)) {
                    mobilePayRequest.setApiKey(p.getValue());
                }
            });
        }

        //生成用于缓存Key的随机字符串，并作为透传参数传递给微信支付，在返回时从缓存中查询秘钥信息
        if (StringUtils.isEmpty(mobilePayRequest.getNonce())) {
            mobilePayRequest.setNonce(payCacheService.randomString());
        }

        //缓存支付参数
        payCacheService.cacheWeChatPayParameters(mobilePayRequest.getMemberId(), mobilePayRequest.getMemberRoleId(), mobilePayRequest.getPayType(), mobilePayRequest.getNonce(), mobilePayRequest.getMerchantId(), mobilePayRequest.getAppId(), mobilePayRequest.getApiKey());

        //实例化WxPayService
        WxPayService wxPayService = new WxPayServiceImpl();
        WxPayConfig payConfig = new WxPayConfig();
        payConfig.setMchId(mobilePayRequest.getMerchantId());
        payConfig.setAppId(mobilePayRequest.getAppId());
        payConfig.setMchKey(mobilePayRequest.getApiKey());
        wxPayService.setConfig(payConfig);

        //封装微信附加数据
        AttachInfo attachInfo = new AttachInfo();
        attachInfo.setPayType(payType);
        attachInfo.setMemberId(memberId);
        attachInfo.setMemberRoleId(memberRoleId);
        attachInfo.setAttach(attach);
        attachInfo.setServiceType(serviceType);
        String attachJson = payCacheService.serializeObject(attachInfo);

        try {
            //封装参数
            String nonceStr = WeChatPayUtil.getNonceStr();
            WxPayUnifiedOrderRequest wxPayUnifiedOrderRequest = new WxPayUnifiedOrderRequest();
            wxPayUnifiedOrderRequest.setAppid(mobilePayRequest.getAppId());
            wxPayUnifiedOrderRequest.setMchId(mobilePayRequest.getMerchantId());
            wxPayUnifiedOrderRequest.setNonceStr(nonceStr);
            wxPayUnifiedOrderRequest.setBody(remark);
            wxPayUnifiedOrderRequest.setOutTradeNo(orderCode);
            wxPayUnifiedOrderRequest.setTotalFee(new Double(payMoney * 100).intValue());
            wxPayUnifiedOrderRequest.setSpbillCreateIp(WeChatPayUtil.getRemoteAddrIp(request));
            wxPayUnifiedOrderRequest.setNotifyUrl(payGateWayConfig.getNotifyUrl() + WeChatPayUtil.notifyUrl);
            wxPayUnifiedOrderRequest.setTradeType(WeChatPayUtil.APP);
            if (StringUtils.isNotEmpty(attachJson)) {
                wxPayUnifiedOrderRequest.setAttach(attachJson);
            }
            String unifiedOrderSign = SignUtils.createSign(wxPayUnifiedOrderRequest, "MD5", mobilePayRequest.getApiKey(), null);
            wxPayUnifiedOrderRequest.setSign(unifiedOrderSign);

            WxPayUnifiedOrderResult wxPayUnifiedOrderResult = wxPayService.unifiedOrder(wxPayUnifiedOrderRequest);
            String returnCode = wxPayUnifiedOrderResult.getReturnCode();
            String returnMsg = wxPayUnifiedOrderResult.getReturnMsg();
            String resultCode = wxPayUnifiedOrderResult.getResultCode();
            String errCodeDes = wxPayUnifiedOrderResult.getErrCodeDes();
            String prepayId = wxPayUnifiedOrderResult.getPrepayId();
            if (WeChatPayUtil.SUCCESS.equals(returnCode)) {
                //验证支付结果
                if (WeChatPayUtil.SUCCESS.equals(resultCode)) {
                    //获取统一下单接口返回的prepay_id
                    WxPayAppOrderResult wxPayAppOrderResult = new WxPayAppOrderResult();
                    wxPayAppOrderResult.setAppId(mobilePayRequest.getAppId());
                    wxPayAppOrderResult.setNonceStr(nonceStr);
                    wxPayAppOrderResult.setTimeStamp(String.valueOf(System.currentTimeMillis() / 1000));
                    wxPayAppOrderResult.setPrepayId(prepayId);
                    String wxPayAppOrderSign = SignUtils.createSign(wxPayAppOrderResult, "MD5", mobilePayRequest.getApiKey(), null);
                    wxPayAppOrderResult.setPartnerId(mobilePayRequest.getMerchantId());
                    wxPayAppOrderResult.setPackageValue("Sign=WXPay");
                    wxPayAppOrderResult.setSign(wxPayAppOrderSign);
                    return new PayResult(true, wxPayAppOrderResult);
                } else {
                    return new PayResult(false, errCodeDes);
                }
            }
            //返回错误信息
            return new PayResult(false, returnMsg);
        } catch (Exception e) {
            e.printStackTrace();
            throw new BusinessException(ResponseCode.PAY_MEMBER_PAY_FAIL);
        }
    }

    /**
     * 查询订单
     */
    @Override
    public PayResult orderQuery(WeChatOrderQueryRequest weChatOrderQueryRequest) {
        try {
            //获取参数
            Long memberId = weChatOrderQueryRequest.getMemberId();
            Long memberRoleId = weChatOrderQueryRequest.getMemberRoleId();
            String outTradeNo = weChatOrderQueryRequest.getOutTradeNo();
            String transactionId = weChatOrderQueryRequest.getTransactionId();
            Integer payType = weChatOrderQueryRequest.getPayType();
            //从订单服务查询支付参数
            OrderPayParameterFeignVO feignVO = new OrderPayParameterFeignVO();
            feignVO.setMemberId(memberId);
            feignVO.setRoleId(memberRoleId);
            feignVO.setPayChannel(OrderPayChannelEnum.WECHAT_PAY);
            Wrapper<PaymentParameterFeignDetailVO> parameterResult = orderFeignService.findPaymentParameters(feignVO);
            if (parameterResult.getCode() != ResponseCode.SUCCESS.getCode()) {
                return new PayResult(false, parameterResult.getMessage());
            }

            if (CollectionUtils.isEmpty(parameterResult.getData().getParameters())) {
                return new PayResult(false, ResponseCode.PAY_PLATFORM_PARAMETERS_DOES_NOT_EXIST.getMessage());
            }

            WxPayConfig payConfig = new WxPayConfig();
            parameterResult.getData().getParameters().stream().filter(p -> p.getParameter().equals(OrderPaymentParameterEnum.WECHAT_MERCHANT_ID)).findFirst().ifPresent(p -> payConfig.setMchId(p.getValue()));
            parameterResult.getData().getParameters().stream().filter(p -> p.getParameter().equals(OrderPaymentParameterEnum.WECHAT_APP_ID)).findFirst().ifPresent(p -> payConfig.setAppId(p.getValue()));
            parameterResult.getData().getParameters().stream().filter(p -> p.getParameter().equals(OrderPaymentParameterEnum.WECHAT_API_KEY)).findFirst().ifPresent(p -> payConfig.setMchKey(p.getValue()));

            //实例化WxPayService
            WxPayService wxPayService = new WxPayServiceImpl();
            wxPayService.setConfig(payConfig);

            //封装参数
            WxPayOrderQueryRequest request = new WxPayOrderQueryRequest();
            request.setAppid(payConfig.getAppId());                                                  //程序ID
            request.setMchId(payConfig.getMchId());                                                  //商户号
            request.setNonceStr(WeChatPayUtil.getNonceStr());                                        //随机字符串
            request.setTransactionId(transactionId);                                                 //微信订单号
            request.setOutTradeNo(outTradeNo);                                                       //商户订单号
            request.setSign(WeChatPayUtil.sign(request, "MD5", payConfig.getMchKey()));     //签名
            WxPayOrderQueryResult orderQueryResult = wxPayService.queryOrder(request);
            //验证返回结果
            String returnCode = orderQueryResult.getReturnCode();
            if (WeChatPayUtil.SUCCESS.equals(returnCode)) {
                //验证结果
                String resultCode = orderQueryResult.getResultCode();
                if (WeChatPayUtil.SUCCESS.equals(resultCode)) {
                    return new PayResult(true, orderQueryResult);
                } else {
                    return new PayResult(false, orderQueryResult.getErrCodeDes());
                }
            }
            //返回错误信息
            return new PayResult(false, orderQueryResult.getReturnMsg());
        } catch (WxPayException e) {
            String errCode = e.getErrCode();
            if (StringUtils.isNotEmpty(errCode)) {
                return new PayResult(false, WechatErrorEnum.getMessage(e.getErrCode()));
            } else {
                return new PayResult(false, e.getMessage());
            }
        }
    }

    /**
     * 关闭订单
     */
    @Override
    public PayResult closeOrder(WeChatCloseOrderRequest weChatCloseOrderRequest) {
        try {
            //获取参数
            Long memberId = weChatCloseOrderRequest.getMemberId();
            Long memberRoleId = weChatCloseOrderRequest.getMemberRoleId();
            String outTradeNo = weChatCloseOrderRequest.getOutTradeNo();
            Integer payType = weChatCloseOrderRequest.getPayType();

            //从订单服务查询支付参数
            OrderPayParameterFeignVO feignVO = new OrderPayParameterFeignVO();
            feignVO.setMemberId(memberId);
            feignVO.setRoleId(memberRoleId);
            feignVO.setPayChannel(OrderPayChannelEnum.WECHAT_PAY);
            Wrapper<PaymentParameterFeignDetailVO> parameterResult = orderFeignService.findPaymentParameters(feignVO);
            if (parameterResult.getCode() != ResponseCode.SUCCESS.getCode()) {
                return new PayResult(false, parameterResult.getMessage());
            }

            if (CollectionUtils.isEmpty(parameterResult.getData().getParameters())) {
                return new PayResult(false, ResponseCode.PAY_PLATFORM_PARAMETERS_DOES_NOT_EXIST.getMessage());
            }

            WxPayConfig payConfig = new WxPayConfig();
            parameterResult.getData().getParameters().stream().filter(p -> p.getParameter().equals(OrderPaymentParameterEnum.WECHAT_MERCHANT_ID)).findFirst().ifPresent(p -> payConfig.setMchId(p.getValue()));
            parameterResult.getData().getParameters().stream().filter(p -> p.getParameter().equals(OrderPaymentParameterEnum.WECHAT_APP_ID)).findFirst().ifPresent(p -> payConfig.setAppId(p.getValue()));
            parameterResult.getData().getParameters().stream().filter(p -> p.getParameter().equals(OrderPaymentParameterEnum.WECHAT_API_KEY)).findFirst().ifPresent(p -> payConfig.setMchKey(p.getValue()));

            //实例化WxPayService
            WxPayService wxPayService = new WxPayServiceImpl();
            wxPayService.setConfig(payConfig);

            //封装参数
            WxPayOrderCloseRequest request = new WxPayOrderCloseRequest();
            request.setAppid(payConfig.getAppId());                                                  //程序ID
            request.setMchId(payConfig.getMchId());                                                  //商户号
            request.setNonceStr(WeChatPayUtil.getNonceStr());                                        //随机字符串
            request.setOutTradeNo(outTradeNo);                                                       //商户订单号
            request.setSign(WeChatPayUtil.sign(request, "MD5", payConfig.getMchKey()));     //签名
            WxPayOrderCloseResult orderCloseResult = wxPayService.closeOrder(request);
            //验证返回结果
            String returnCode = orderCloseResult.getReturnCode();
            if (WeChatPayUtil.SUCCESS.equals(returnCode)) {
                //验证支付结果
                String resultCode = orderCloseResult.getResultCode();
                if (WeChatPayUtil.SUCCESS.equals(resultCode)) {
                    return new PayResult(true, orderCloseResult);
                } else {
                    return new PayResult(false, orderCloseResult.getErrCodeDes());
                }
            }
            //返回错误信息
            return new PayResult(false, orderCloseResult.getReturnMsg());
        } catch (WxPayException e) {
            String errCode = e.getErrCode();
            if (StringUtils.isNotEmpty(errCode)) {
                return new PayResult(false, WechatErrorEnum.getMessage(e.getErrCode()));
            } else {
                return new PayResult(false, e.getMessage());
            }
        }
    }

    /**
     * 申请退款
     */
    @Override
    public PayResult refund(WeChatRefundRequest weChatRefundRequest) {
        try {
            //获取参数
            Long memberId = weChatRefundRequest.getMemberId();
            Long memberRoleId = weChatRefundRequest.getMemberRoleId();
//            String outTradeNo = weChatRefundRequest.getOutTradeNo();
//            String transactionId = weChatRefundRequest.getTransactionId();
            String outTradeNo = StringUtils.isEmpty(weChatRefundRequest.getOutTradeNo()) ? "" : weChatRefundRequest.getOutTradeNo();
            String transactionId = StringUtils.isEmpty(weChatRefundRequest.getTransactionId()) ? "" : weChatRefundRequest.getTransactionId();

            Double payMoney = weChatRefundRequest.getPayMoney();
            String outRefundNo = weChatRefundRequest.getOutRefundNo();
            Double refundMoney = weChatRefundRequest.getRefundMoney();
            Integer payType = weChatRefundRequest.getPayType();
            //从订单服务查询支付参数
            if (StringUtils.isAnyEmpty(weChatRefundRequest.getMerchantId(), weChatRefundRequest.getApiKey(), weChatRefundRequest.getAppId(), weChatRefundRequest.getKeyPath())) {
                OrderPayParameterFeignVO feignVO = new OrderPayParameterFeignVO();
                feignVO.setMemberId(weChatRefundRequest.getMemberId());
                feignVO.setRoleId(weChatRefundRequest.getMemberRoleId());
                feignVO.setPayChannel(OrderPayChannelEnum.WECHAT_PAY);
                Wrapper<PaymentParameterFeignDetailVO> parameterResult = orderFeignService.findPaymentParameters(feignVO);
                if (parameterResult.getCode() != ResponseCode.SUCCESS.getCode()) {
                    return new PayResult(false, parameterResult.getMessage());
                }

                if (CollectionUtils.isEmpty(parameterResult.getData().getParameters())) {
                    return new PayResult(false, ResponseCode.PAY_PLATFORM_PARAMETERS_DOES_NOT_EXIST.getMessage());
                }

                parameterResult.getData().getParameters().forEach(p -> {
                    if (p.getParameter().equals(OrderPaymentParameterEnum.WECHAT_MERCHANT_ID)) {
                        weChatRefundRequest.setMerchantId(p.getValue());
                    } else if (p.getParameter().equals(OrderPaymentParameterEnum.WECHAT_APP_ID)) {
                        weChatRefundRequest.setAppId(p.getValue());
                    } else if (p.getParameter().equals(OrderPaymentParameterEnum.WECHAT_API_KEY)) {
                        weChatRefundRequest.setApiKey(p.getValue());
                    } else if (p.getParameter().equals(OrderPaymentParameterEnum.WECHAT_KEY_PATH)) {
                        weChatRefundRequest.setKeyPath(p.getValue());
                    }
                });
            }

            WxPayConfig payConfig = new WxPayConfig();
            payConfig.setMchId(weChatRefundRequest.getMerchantId());
            payConfig.setAppId(weChatRefundRequest.getAppId());
            payConfig.setMchKey(weChatRefundRequest.getApiKey());
            payConfig.setKeyPath(weChatRefundRequest.getKeyPath());

            //实例化WxPayService
            WxPayService wxPayService = new WxPayServiceImpl();
            wxPayService.setConfig(payConfig);

            //封装参数
            WxPayRefundRequest request = new WxPayRefundRequest();
            request.setAppid(payConfig.getAppId());                                                  //程序ID
            request.setMchId(payConfig.getMchId());                                                  //商户号
            request.setNonceStr(WeChatPayUtil.getNonceStr());                                        //随机字符串
            if (StringUtils.isNotEmpty(transactionId)) {
                request.setTransactionId(transactionId);                                             //微信订单号
            } else {
                request.setOutTradeNo(outTradeNo);                                                   //商户订单号
            }
            request.setTotalFee(new Double(payMoney * 100).intValue());                        //订单金额
            request.setOutRefundNo(outRefundNo);                                                     //商户退款单号
            request.setRefundFee(new Double(refundMoney * 100).intValue());                    //退款金额
            request.setSign(WeChatPayUtil.sign(request, "MD5", payConfig.getMchKey()));     //签名
            WxPayRefundResult refundResult = wxPayService.refund(request);
            //验证返回结果
            String returnCode = refundResult.getReturnCode();
            if (WeChatPayUtil.SUCCESS.equals(returnCode)) {
                //验证支付结果
                String resultCode = refundResult.getResultCode();
                if (WeChatPayUtil.SUCCESS.equals(resultCode)) {
                    return new PayResult(true, refundResult.getRefundId());
                } else {
                    return new PayResult(false, refundResult.getErrCodeDes());
                }
            }
            //返回错误信息
            return new PayResult(false, refundResult.getReturnMsg());
        } catch (WxPayException e) {
            String errCode = e.getErrCode();
            if (StringUtils.isNotEmpty(errCode)) {
                return new PayResult(false, WechatErrorEnum.getMessage(e.getErrCode()));
            } else {
                return new PayResult(false, e.getMessage());
            }
        }
    }

    /**
     * 退款查询
     */
    @Override
    public PayResult refundQuery(WeChatRefundQueryRequest weChatRefundQueryRequest) {
        try {
            //获取参数
            Long memberId = weChatRefundQueryRequest.getMemberId();
            Long memberRoleId = weChatRefundQueryRequest.getMemberRoleId();
            String outTradeNo = weChatRefundQueryRequest.getOutTradeNo();
            String transactionId = weChatRefundQueryRequest.getTransactionId();
            String outRefundNo = weChatRefundQueryRequest.getOutRefundNo();
            String refundId = weChatRefundQueryRequest.getRefundId();
            Integer payType = weChatRefundQueryRequest.getPayType();
            //从订单服务查询支付参数
            OrderPayParameterFeignVO feignVO = new OrderPayParameterFeignVO();
            feignVO.setMemberId(memberId);
            feignVO.setRoleId(memberRoleId);
            feignVO.setPayChannel(OrderPayChannelEnum.WECHAT_PAY);
            Wrapper<PaymentParameterFeignDetailVO> parameterResult = orderFeignService.findPaymentParameters(feignVO);
            if (parameterResult.getCode() != ResponseCode.SUCCESS.getCode()) {
                return new PayResult(false, parameterResult.getMessage());
            }

            if (CollectionUtils.isEmpty(parameterResult.getData().getParameters())) {
                return new PayResult(false, ResponseCode.PAY_PLATFORM_PARAMETERS_DOES_NOT_EXIST.getMessage());
            }

            WxPayConfig payConfig = new WxPayConfig();
            parameterResult.getData().getParameters().stream().filter(p -> p.getParameter().equals(OrderPaymentParameterEnum.WECHAT_MERCHANT_ID)).findFirst().ifPresent(p -> payConfig.setMchId(p.getValue()));
            parameterResult.getData().getParameters().stream().filter(p -> p.getParameter().equals(OrderPaymentParameterEnum.WECHAT_APP_ID)).findFirst().ifPresent(p -> payConfig.setAppId(p.getValue()));
            parameterResult.getData().getParameters().stream().filter(p -> p.getParameter().equals(OrderPaymentParameterEnum.WECHAT_API_KEY)).findFirst().ifPresent(p -> payConfig.setMchKey(p.getValue()));

            //实例化WxPayService
            WxPayService wxPayService = new WxPayServiceImpl();
            wxPayService.setConfig(payConfig);

            //封装参数
            WxPayRefundQueryRequest request = new WxPayRefundQueryRequest();
            request.setAppid(payConfig.getAppId());                                                  //程序ID
            request.setMchId(payConfig.getMchId());                                                  //商户号
            request.setNonceStr(WeChatPayUtil.getNonceStr());                                        //随机字符串
            request.setTransactionId(transactionId);                                                 //微信订单号
            request.setOutTradeNo(outTradeNo);                                                       //商户订单号
            request.setOutRefundNo(outRefundNo);                                                     //商户退款单号
            request.setRefundId(refundId);                                                           //微信退款单号
            request.setSign(WeChatPayUtil.sign(request, "MD5", payConfig.getMchKey()));     //签名
            WxPayRefundQueryResult refundQueryResult = wxPayService.refundQuery(request);
            //验证返回结果
            String returnCode = refundQueryResult.getReturnCode();
            if (WeChatPayUtil.SUCCESS.equals(returnCode)) {
                //验证支付结果
                String resultCode = refundQueryResult.getResultCode();
                if (WeChatPayUtil.SUCCESS.equals(resultCode)) {
                    return new PayResult(true, refundQueryResult);
                } else {
                    return new PayResult(false, refundQueryResult.getErrCodeDes());
                }
            }
            //返回错误信息
            return new PayResult(false, refundQueryResult.getReturnMsg());
        } catch (WxPayException e) {
            String errCode = e.getErrCode();
            if (StringUtils.isNotEmpty(errCode)) {
                return new PayResult(false, WechatErrorEnum.getMessage(e.getErrCode()));
            } else {
                return new PayResult(false, e.getMessage());
            }
        }
    }

    /**
     * 获取微信AccessToken
     * 先从缓存中获取，如果缓存中没有，则再请求微信接口，再缓存
     * @param accessTokenRequest
     * @return
     */
    @Override
    public AccessToken getWeChatAccessToken(AccessTokenRequest accessTokenRequest) {
        if (StringUtils.isAnyEmpty(accessTokenRequest.getAppId(),accessTokenRequest.getAppSecret())) {
            OrderPayChannelFeignVO orderPayChannelFeignVO = new OrderPayChannelFeignVO();
            orderPayChannelFeignVO.setPayChannel(OrderPayChannelEnum.WECHAT_PAY);
            Wrapper<PaymentParameterFeignDetailVO> parameterResult = orderFeignService.findPlatformPaymentParameters(orderPayChannelFeignVO);
            parameterResult.getData().getParameters().stream().filter(p -> p.getParameter().equals(OrderPaymentParameterEnum.WECHAT_PUBLIC_APP_ID)).findFirst().ifPresent(p -> accessTokenRequest.setAppId(p.getValue()));
            parameterResult.getData().getParameters().stream().filter(p -> p.getParameter().equals(OrderPaymentParameterEnum.WECHAT_PUBLIC_API_KEY)).findFirst().ifPresent(p -> accessTokenRequest.setAppSecret(p.getValue()));
            if (Objects.isNull(accessTokenRequest.getAppId()) || Objects.isNull(accessTokenRequest.getAppSecret())) {
                throw new BusinessException(ResponseCode.PUBLIC_PAY_CONFIG_NOT_FOUND);
            }
        }
        String accessTokenKey = accessTokenRequest.getAppId() + "_" + accessTokenRequest.getAppSecret() + "_" + "access_token";
        AccessToken accessToken = redisUtils.get(accessTokenKey, Constants.REDIS_PAY_INDEX, AccessToken.class);
        if (Objects.isNull(accessToken)) {
            accessToken = getAccessTokenFromWechat(accessTokenRequest);
            redisUtils.set(accessTokenKey, JSONUtil.toJsonStr(accessToken), (long) accessToken.getExpiresIn(), Constants.REDIS_PAY_INDEX);
        }
        return accessToken;
    }

    /**
     * 从微信中请求AccessToken
     * @param accessTokenRequest
     * @return
     */
    private AccessToken getAccessTokenFromWechat(AccessTokenRequest accessTokenRequest) {
        AccessToken accessToken = new AccessToken();
        String requestUrl = access_token_url.replace("APPID", accessTokenRequest.getAppId()).replace("APPSECRET", accessTokenRequest.getAppSecret());
        String result = restTemplateUtil.doGet(requestUrl);
        if (Objects.nonNull(result)) {
            logger.info("==========获取accessToken返回结果：" + result + "==========");
            JSONObject resultObject = JSONUtil.parseObj(result);
            String token = resultObject.getStr("access_token");
            Integer expiresIn = resultObject.getInt("expires_in");
            if (Objects.isNull(token)||Objects.isNull(expiresIn)) {
                throw new BusinessException(result);
            }
            accessToken.setToken(token);
            accessToken.setExpiresIn(expiresIn);
        }
        return accessToken;
    }

    /**
     * 获取微信JsApiTicket
     *
     * @param accessTokenRequest
     * @return
     */
    @Override
    public JsApiTicket getJsApiTicket(AccessTokenRequest accessTokenRequest) {
        JsApiTicket jsApiTicket = new JsApiTicket();
        AccessToken accessToken = null;
        String accessTokenKey = accessTokenRequest.getAppId() + "_" + accessTokenRequest.getAppSecret() + "_" + "access_token";
        accessToken = redisUtils.get(accessTokenKey, Constants.REDIS_PAY_INDEX, AccessToken.class);
        if (Objects.isNull(accessToken)) {
            accessToken = getWeChatAccessToken(accessTokenRequest);
            redisUtils.set(accessTokenKey, JSONUtil.toJsonStr(accessToken), (long) accessToken.getExpiresIn(), Constants.REDIS_PAY_INDEX);
        }
        String token = accessToken.getToken();
        String requestUrl = ticket_url.replace("ACCESS_TOKEN", token);
        String result = restTemplateUtil.doGet(requestUrl);
        if (Objects.nonNull(result)) {
            JSONObject resultObject = JSONUtil.parseObj(result);
            jsApiTicket.setTicket(resultObject.getStr("ticket"));
            jsApiTicket.setExpiresIn(resultObject.getInt("expires_in"));
        }
        return jsApiTicket;
    }

    /**
     * 获取JS-SDK签名
     *
     * @param jsApiRequest
     * @return
     */
    @Override
    public JsApiResult getJsApiResult(JsApiRequest jsApiRequest) {
        //jsApiTicket
        JsApiTicket jsApiTicket = null;
        String jsApiTicketKey = jsApiRequest.getAppId() + "_" + jsApiRequest.getAppSecret() + "_" + "jsApiTicket";
        jsApiTicket = redisUtils.get(jsApiTicketKey, Constants.REDIS_PAY_INDEX, JsApiTicket.class);
        if (Objects.isNull(jsApiTicket)) {
            jsApiTicket = getJsApiTicket(jsApiRequest);
            redisUtils.set(jsApiTicketKey, JSONUtil.toJsonStr(jsApiTicket), (long) jsApiTicket.getExpiresIn(), Constants.REDIS_PAY_INDEX);
        }
        //当前网页URL
        String url = jsApiRequest.getUrl();
        System.out.println(url);
        try {
            url = URLDecoder.decode(url, "UTF-8");
            System.out.println(url);
        }catch (Exception e) {
            logger.error(e.getMessage());
        }
        //签名随机串
        String nonceStr = WeChatPayUtil.getNonceStr();
        //当前时间戳
        long time = DateUtil.current(false) / 1000;
        String timestamp = String.format("%010d", time);
        StringBuilder result = new StringBuilder();
        result.append("jsapi_ticket="+jsApiTicket.getTicket());
        result.append("&");
        result.append("noncestr=" + nonceStr);
        result.append("&");
        result.append("timestamp=" + timestamp);
        result.append("&");
        result.append("url="+url);
        System.out.println(result.toString());
        //加密
        String signature = DigestUtil.sha1Hex(result.toString());

        JsApiResult jsApiResult = new JsApiResult();
        jsApiResult.setAppId(jsApiRequest.getAppId());
        jsApiResult.setTimestamp(timestamp);
        jsApiResult.setNonceStr(nonceStr);
        jsApiResult.setSignature(signature);

        return jsApiResult;
    }

    @Override
    public String getUrlLink(UrlLinkDTO urlLinkDTO) {
        String appLetAppId = "";//小程序appid
        String appLetAppKey = "";//小程序密钥

        //从缓存中获取微信支付参数
        OrderPayChannelFeignVO vo = new OrderPayChannelFeignVO();
        vo.setPayChannel(OrderPayChannelEnum.WECHAT_PAY);
        Wrapper<PaymentParameterFeignDetailVO> parameters = orderFeignService.findPlatformPaymentParameters(vo);
        if (parameters.getCode() != ResponseCode.SUCCESS.getCode()) {
            throw new BusinessException(parameters.getCode(), parameters.getMessage());
        }
        List<PayChannelParameterFeignDetailVO> list = parameters.getData().getParameters();
        if (CollectionUtils.isEmpty(list)) {
            throw new BusinessException(ResponseCode.PAY_PLATFORM_PARAMETERS_DOES_NOT_EXIST);
        }
        for (PayChannelParameterFeignDetailVO p : list) {
            if (p.getParameter().equals(OrderPaymentParameterEnum.WECHAT_APPLET_APP_ID)) {
                appLetAppId = p.getValue();
            } else if (p.getParameter().equals(OrderPaymentParameterEnum.WECHAT_APPLET_APP_KEY)) {
                appLetAppKey = p.getValue();
            }

        }
        //配置请求链接
        String requestUrl = access_token_url.replace("APPID", appLetAppId).replace("APPSECRET", appLetAppKey);
        String result = restTemplateUtil.doGet(requestUrl);
        if (Objects.nonNull(result)) {
            JSONObject resultObject = JSONUtil.parseObj(result);
            String accessToken = resultObject.getStr("access_token");
            //配置请求链接
            String generateUrlLink = generate_url_link.replace("ACCESS_TOKEN", accessToken);
            //根据accessToken获取url_link
            Map<String, Object> map = new HashMap<>();
            map.put("path",urlLinkDTO.getPath());
            map.put("env_version","trial");
            map.put("is_expire",urlLinkDTO.getIsExpire());
            map.put("expire_type",urlLinkDTO.getExpireType());
            map.put("expire_time",urlLinkDTO.getExpireTime());
            map.put("expire_interval",urlLinkDTO.getExpireInterval());
            map.put("cloud_base",urlLinkDTO.getCloudBase());
            String resp = restTemplateUtil.doPost(generateUrlLink,map, null);
            JSONObject jsonObject = JSONUtil.parseObj(resp);
            if (jsonObject.getInt("errcode") == 0) {
                return jsonObject.getStr("url_link");
            } else {
                throw new BusinessException(jsonObject.getInt("errcode"), jsonObject.getStr("errmsg"));
            }
        }
        return null;
    }
}
